package com.bsj.power.pls.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.bsj.power.common.config.cached.RedisCached;
import com.bsj.power.common.config.global.JsonResult;
import com.bsj.power.common.config.global.JsonResultEnum;
import com.bsj.power.common.config.redis.RedisConstant;
import com.bsj.power.common.constant.NumericalConstants;
import com.bsj.power.common.def.entity.gpgga.Gpgga;
import com.bsj.power.common.mapper.GpggaMapper;
import com.bsj.power.pls.config.net.netty.gpgga.GpggaParsingData;
import com.bsj.power.pls.config.net.netty.gpgga.StartGpgga;
import com.bsj.power.pls.service.ScheduledTasksService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;

/**
 * @author LiJiaXin
 * @version 1.0.0
 * @description ScheduledTasksServiceImpl
 * @time 2024/11/27 20:37
 */
@Slf4j
@Service
public class ScheduledTasksServiceImpl implements ScheduledTasksService {

    @Value("${scheduledTasks.isExecute}")
    private boolean isExecute;

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private RedisCached redisCached;

    @Resource
    private GpggaMapper gpggaMapper;

    /**
     * 项目自启动，初始化定时器
     *
     * @throws SchedulerException
     */
    @PostConstruct
    public void init() throws SchedulerException {
        scheduler.clear();
        // 启动调度器
        scheduler.start();
        Integer second;
        // 动态添加定时任务
        String str = redisCached.get(RedisConstant.SHAPE_VARIABLE_SYNC_TIME);
        if (StringUtils.isBlank(str)) {
            second = 30 * 60;
            redisCached.set(RedisConstant.SHAPE_VARIABLE_SYNC_TIME, second);
        } else {
            second = Integer.parseInt(str);
        }
        addJob(scheduler, "shapeVariableComputation", "shapeVariableAdd", MyScheduledTasks.class, second);
    }

    public class MyScheduledTasks implements Job {
        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            //具体的任务
            if (isExecute) {
                shapeVariableTasks();
            }
        }
    }

    /**
     * 获取计算好的形变量
     *
     * @return void
     * @author ljx
     * @time 2024/11/28 10:03
     */
    public void shapeVariableTasks() {
        computationShapeVariable(NumericalConstants.ONE);
        computationShapeVariable(NumericalConstants.TWO);
    }

    /**
     * 计算形变量
     *
     * @param number
     * @return void
     * @author ljx
     * @time 2024/11/28 10:13
     */
    private void computationShapeVariable(Integer number) {
        log.info(number + "号机组形变量计算开始");
        String shapeVariableStr = redisCached.get(RedisConstant.SHAPE_VARIABLE_INFO_KEY + number);
        if (StringUtils.isBlank(shapeVariableStr)) {
            return;
        }
        //经度纬度高度
        List<Double> shapeVariable = Arrays.stream(JSONObject.parseObject(shapeVariableStr, String.class).split(",")).map(Double::parseDouble).collect(Collectors.toList());
        //过去一段时间内的GPGGA数据
        List<String> stringList = redisCached.lrange(RedisConstant.GPGGA_DATA_INFO_KEY + number, NumericalConstants.ZERO, NumericalConstants.NEGATIVE_ONE);
        if (CollectionUtils.isEmpty(stringList)) {
            return;
        }
        List<GpggaParsingData> gpggaParsingDataList = stringList.stream().map(str -> {
            return JSONObject.parseObject(str, GpggaParsingData.class);
        }).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(gpggaParsingDataList)) {
            return;
        }
        StartGpgga startGpgga = getStartGpgga(shapeVariable, gpggaParsingDataList);
        Gpgga gpgga = new Gpgga();
        BeanUtils.copyProperties(startGpgga, gpgga);
        log.info(number + "号机组形变量计算结果：{}", gpgga);
        gpgga.setUnitNo(number);
        if (gpggaMapper.insert(gpgga) > NumericalConstants.ZERO) {
            //缓存新的形变量
//            shapeVariableStr = startGpgga.getLongitude() + "," + startGpgga.getLatitude() + "," + startGpgga.getAltitude();
//            log.info(number + "号机组新的经纬高：{}", shapeVariableStr);
//            redisCached.set(RedisConstant.SHAPE_VARIABLE_INFO_KEY + number, shapeVariableStr);
            //清除上一时间段的GPGGA数据
            redisCached.del(RedisConstant.GPGGA_DATA_INFO_KEY + number);
            log.info(number + "号机组GPGGA数据清除成功");
        }
    }

    /**
     * 正式计算
     *
     * @param shapeVariable
     * @param list
     * @return com.bsj.power.pls.gpgga.StartGpgga
     * @author ljx
     * @time 2024/11/28 10:26
     */
    private StartGpgga getStartGpgga(List<Double> shapeVariable, List<GpggaParsingData> list) {
        double e = 0;
        double n = 0;
        double u = 0;
        double longitude = 0;
        double latitude = 0;
        double altitude = 0;
        int size = list.size();
        for (GpggaParsingData parsingData : list) {
            e += parsingData.getE();
            n += parsingData.getN();
            u += parsingData.getU();
            longitude += parsingData.getLongitude();
            latitude += parsingData.getLatitude();
            altitude += parsingData.getAltitude();
        }
        StartGpgga startGpgga = new StartGpgga();
        DecimalFormat df = new DecimalFormat("#.0000000000");
        startGpgga.setE(Double.parseDouble(df.format(e / size)));
        startGpgga.setN(Double.parseDouble(df.format(n / size)));
        startGpgga.setU(Double.parseDouble(df.format(u / size)));
        startGpgga.setLongitude(Double.parseDouble(df.format(longitude / size)));
        startGpgga.setLatitude(Double.parseDouble(df.format(latitude / size)));
        startGpgga.setAltitude(Double.parseDouble(df.format(altitude / size)));
        return startGpgga;
    }

    /**
     * 添加定时任务
     *
     * @param scheduler
     * @param jobName
     * @param groupName
     * @param jobClass
     * @param second
     * @return void
     * @author ljx
     * @time 2024/8/26 21:20
     */
    public static void addJob(Scheduler scheduler, String jobName, String groupName, Class<? extends Job> jobClass, Integer second) throws SchedulerException {
        // 定义一个任务
        JobDetail job = newJob(jobClass)
                .withIdentity(jobName, groupName)
                .build();

        // 创建触发器
        Trigger trigger = newTrigger()
                .withIdentity(jobName + "Trigger", groupName)
                .startNow()
                .withSchedule(simpleSchedule()
                        .withIntervalInSeconds(second)
                        .repeatForever())
                .build();

        // 将任务和触发器注册到调度器中
        scheduler.scheduleJob(job, trigger);
    }

    /**
     * 删除定时任务
     *
     * @param scheduler
     * @param jobName
     * @param groupName
     * @return void
     * @author ljx
     * @time 2024/8/26 21:22
     */
    public static void deleteJob(Scheduler scheduler, String jobName, String groupName) throws SchedulerException {
        // 删除任务和触发器
        scheduler.deleteJob(new JobKey(jobName, groupName));
    }

    /**
     * 设置形变量结算时间间隔定时任务
     *
     * @param second
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/11/27 20:40
     */
    @Override
    public JsonResult setShapeVariableTasks(Integer second) throws SchedulerException {
        if (second == null) {
            return JsonResult.fail();
        }
        if (second < 5 * 60) {
            return JsonResult.fail(JsonResultEnum.SMALL_TIME_INTERVAL);
        }
        //设置新的时间
        redisCached.set(RedisConstant.SHAPE_VARIABLE_SYNC_TIME, second);
        //删除原先的任务
        deleteJob(scheduler, "shapeVariableComputation", "shapeVariableAdd");
        //创建新的任务
        addJob(scheduler, "shapeVariableComputation", "shapeVariableAdd", MyScheduledTasks.class, second);
        return JsonResult.success();
    }

    /**
     * 获取形变量结算定时任务时间间隔
     *
     * @return com.bsj.power.common.config.global.JsonResult<java.lang.Integer>
     * @author ljx
     * @time 2024/11/27 20:41
     */
    @Override
    public JsonResult<Integer> getShapeVariableTasksTimeInterval() {
        String str = redisCached.get(RedisConstant.SHAPE_VARIABLE_SYNC_TIME);
        if (StringUtils.isNotBlank(str)) {
            int second = Integer.parseInt(str);
            if (second > NumericalConstants.ZERO) {
                return JsonResult.success(second);
            }
        }
        return JsonResult.success(NumericalConstants.ZERO);
    }
}
